<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <textarea name="" id="source" cols="30" rows="10"></textarea>
    <button onclick="doEncode()">加密</button>
    <button onclick="doDecode()">解密</button>
    <div id="target"></div>

    <script>
      const charset = "嗷呜啊~".split("");
      const LEN = 4;

      function encode(str) {
        let output = [];
        for (let i = 0; i < str.length; i++) {
          const v = str.charCodeAt(i).toString(4).padStart(LEN, "0");
          output.push(
            v
              .split("")
              .map((c) => charset[c])
              .join("")
          );
        }

        return output.join("");
      }

      function decode(str) {
        let output = [];

        let buf = "";
        for (let i = 0; i < str.length; i++) {
          buf += str[i];
          if (buf.length < LEN) {
            continue;
          }

          const code = parseInt(
            buf
              .split("")
              .map((c) => charset.findIndex((v) => v === c))
              .join(""),
            LEN
          );
          console.log(buf, code);
          output.push(code);
          buf = "";
        }

        return String.fromCharCode(...output);
      }

      const $s = document.getElementById("source");
      const $t = document.getElementById("target");

      function doEncode() {
        const v = $s.value;
        $t.innerText = encode(v);
      }

      function doDecode() {
        const v = $s.value;
        $t.innerText = decode(v);
      }
    </script>
  </body>
</html>
